#include "Timing_Wheel.hpp" //时间轮  采用了哈希的技术，将每个定时器的到期时间都注册到一个节点上
#include <sys/epoll.h>
#include <unistd.h>
#include <signal.h>
#include <strings.h>
#include <fcntl.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <memory>
#include <vector>
#include <string.h>
// 全局有一个时间轮

// 信号1秒发一次，总共周期是60s，注册的timeout是10秒会根据当前的cur_slot到后面10的槽中
// 所以信号发10次会清除注册的客户端

#define TIME_SLOT 1
#define MAX_EVENT 1024
#define LIMIT_SOCKFD 65535        // 最大的文件描述符个数
static zj::Time_Wheel timer_list; // 全局的时间轮
static int pipefd[2];             // 用于信号通知服务器定时器到时的管道

int socketpipe()
{
    int ret = socketpair(PF_UNIX, SOCK_STREAM, 0, pipefd);
    if (ret < 0)
    {
        perror("socketpair");
        return -1;
    }
    return 0;
}

class Epoll
{
public:
    Epoll()
    {
        epoll_sockfd = epoll_create(5);
    }

    int Epoll_Wait(struct epoll_event *events)
    {
        return epoll_wait(epoll_sockfd, events, MAX_EVENT, -1);
    }

    void Epoll_Add(int fd)
    {
        epoll_event event;
        event.data.fd = fd;
        event.events = EPOLLET | EPOLLIN;
        int n = epoll_ctl(epoll_sockfd, EPOLL_CTL_ADD, fd, &event);
        if (n == -1)
        {
            std::cout << "epoll_ctl error" << std::endl;
        }
        std::cout << "开始监听fd: " << fd << std::endl;
    }

    void Epoll_del(int fd)
    {
        epoll_ctl(epoll_sockfd, EPOLL_CTL_ADD, fd, 0);
    }

    ~Epoll()
    {
    }

private:
    int epoll_sockfd;
};

class Server_Timer
{
public:
    Server_Timer(std::string ip1, uint16_t port1)
        : ip(ip1),
          port(port1),
          handler_timer_task(false)
    {
        int ret = socketpipe();
        if (ret < 0)
        {
            std::cout << "socketpipe() error" << std::endl;
        }
        std::cout << "ip: " << ip.c_str() << std::endl;
        std::cout << "port: " << port << std::endl;
        _listen_sockfd = socket(PF_INET, SOCK_STREAM, 0);
        sockaddr_in addr;
        bzero(&addr, sizeof(addr));
        addr.sin_family = AF_INET;
        addr.sin_port = htons(port);
        addr.sin_addr.s_addr = INADDR_ANY;
        setSockfdNoBlocking(_listen_sockfd); // 设置非阻塞
        ::bind(_listen_sockfd, (struct sockaddr *)&addr, sizeof(addr));
        ::listen(_listen_sockfd, SOMAXCONN);

        setSockfdNoBlocking(pipefd[0]);

        std::cout << "_listen_sockfd: " << _listen_sockfd << std::endl;
        epoll.Epoll_Add(_listen_sockfd);

        epoll.Epoll_Add(pipefd[0]);

        // std::unique_ptr<User_Data[]> user_datas(new User_Data[LIMIT_SOCKFD]); // 初始化一个智能指针，指向数组首元素
        user_datas = new zj::client_data[LIMIT_SOCKFD];

        addsig(SIGALRM); // 设置信号处理函数

        std::cout << "初始化成功 " << std::endl;
    }

    void func_timer(zj::client_data &user_data) // 每个定时器的回调函数，负责处理用户连接
    {
        std::cout << "调用定时器回调函数" << std::endl;
        std::cout << "user_data.sockfd: " << user_data.sockfd << std::endl;
        epoll.Epoll_del(user_data.sockfd);
        std::cout << "这里没有segmentation" << std::endl;
        char *ip_str = inet_ntoa(user_data.addr.sin_addr);

        uint16_t port = user_data.addr.sin_port;
        // 将 C 风格的字符串转换为 std::string
        std::string ip = ip_str;

        std::cout << "ip: " << ip.c_str() << " port: " << port << "退出" << std::endl;

        close(user_data.sockfd);
    }

    void setSockfdNoBlocking(int fd)
    {
        int fl = fcntl(fd, F_GETFL);
        if (fl < 0)
        {
            perror("fcntl");
            return;
        }
        fcntl(fd, F_SETFL, fl | O_NONBLOCK); // O_NONBLOCK：让该fd，以非阻塞方式进行工作
    }

    void Server_start()
    {
        while (_isrunning)
        {
            std::cout << "Server_start()" << std::endl;
            // 进行处理数据
            struct epoll_event events[MAX_EVENT];
            int number = epoll.Epoll_Wait(events);
            std::cout << "number: " << number << std::endl;
            if (number < 0)
            {
            }
            for (int i = 0; i < number; i++)
            {
                std::cout << events[i].data.fd << std::endl;
                if (events[i].data.fd == _listen_sockfd) // 此时就绪的是监听套接字
                {
                    std::cout << "events[i].data.fd == _listen_sockfd" << std::endl;
                    sockaddr_in addr1;
                    socklen_t len = sizeof(addr1);
                    int sockfd1 = ::accept(_listen_sockfd, (sockaddr *)&addr1, &len);
                    if (sockfd1 < 0)
                    {
                        std::cout << "accept error" << std::endl;
                        break;
                    }
                    std::cout << "sockfd1: " << sockfd1 << std::endl;
                    setSockfdNoBlocking(sockfd1);

                    std::cout << user_datas[sockfd1].getsockfd() << std::endl;
                    user_datas[sockfd1].setaddr(addr1);
                    user_datas[sockfd1].sockfd = sockfd1;

                    // 这里是想要生成一个timer给client，同时add进入时间轮中
                    zj::tw_timer *timer = timer_list.get_timer(TIME_SLOT * 10); // 获得一个timer;
                    timer->cli = &(user_datas)[sockfd1];
                    timer->handler = [this](zj::client_data *user_data) { /// 可调用对象要接受一个User_Data* user_data参数，返回值要是void就行了
                        /// 这里传可调用对象lambda给timer->handler，只需要保证参数和返回值就行，函数体自己实现
                        this->func_timer(*user_data); // 解引用指针   using func_t = std::function<void(User_Data *)>;
                        // func_t先告诉接受一个User_Data* user_data参数，返回值要是void就行了,在可调用对象lambda赋值的时候可支配的就是函数体
                    };
                    (user_datas)[sockfd1].timer = timer;
                    epoll.Epoll_Add(sockfd1);

                    timer_list.add_timer(timer); // 将timer添加进时间轮中，从建立连接epoll进行监听的时候进行计时*/
                }
                if (events[i].data.fd == pipefd[0] && events[i].events & EPOLLIN) // 当管道读就绪
                {
                    std::cout << "events[i].data.fd == pipefd[0]" << std::endl;
                    handler_timer_task = true; // 进行定时器处理设置为true
                }
                if (events[i].data.fd != pipefd[0] && events[i].data.fd != _listen_sockfd && events[i].events & EPOLLIN) // 当用户读就绪
                {
                    // memset((void*)(user_datas)[events[i].data.fd].buffer.c_str(), 0, sizeof(user_datas[events[i].data.fd].buffer));
                    std::cout << "用户读就绪" << std::endl;
                    std::cout << "events[i].data.fd: " << events[i].data.fd << std::endl;

                    zj::tw_timer *timer = user_datas[events[i].data.fd].timer;
                    if (timer == nullptr)
                        break;
                    while (true)
                    {
                        std::cout << "进来了" << std::endl;

                        char buffer1[1024];
                        int ret = ::recv(events[i].data.fd, buffer1, sizeof(buffer1) - 1, 0);
                        buffer1[ret] = 0;
                        std::cout << "1" << std::endl;     // 用户缓冲区
                        std::cout << buffer1 << std::endl; // 用户缓冲区

                        std::cout << "ret: " << ret << std::endl;
                        if (ret < 0)
                        {
                            if (errno == EAGAIN | errno == EWOULDBLOCK) // 因为非阻塞是循环读取的，所以当底层数据读结束时不会等待直接返回
                            {
                                std::cout << "底层数据读取完毕" << std::endl;
                                break;
                            }
                            else if (errno == EINTR)
                            {
                                std::cout << "信号中断" << std::endl;
                                continue;
                            }
                            else
                            {
                                // recv出错，删除定时器
                                std::cout << "recv出错" << std::endl;
                                timer->handler(timer->cli);
                                timer_list.del_timer(timer);
                                break;
                            }
                        }
                        if (ret == 0)
                        {
                            std::cout << "对端客户端断开连接" << std::endl;
                            timer->handler(timer->cli);
                            timer_list.del_timer(timer);
                            break;
                        }
                        else if (ret > 0)
                        {
                            user_datas[events[i].data.fd].buffer += buffer1;
                            std::cout << "user_datas[events[i].data.fd].buffer" << user_datas[events[i].data.fd].buffer.c_str() << std::endl;

                            // 先不允许修改时间，定时开始
                            // 其实修改貌似很简单，就是先删除，在去添加

                            // 此时就要修改定时器的状态，因为对方发送数据来了

                            std::cout << "修改定时时间" << std::endl;
                            int new_timeout = TIME_SLOT * 30;
                            timer_list.adjust_timer(timer, new_timeout);
                            std::cout << "修改定时时间，修改位置完成" << std::endl;
                            // break;
                        }
                    }
                    if (user_datas[events[i].data.fd].buffer.size() > 0)
                    {
                        std::string task_message = "echo# " + user_datas[events[i].data.fd].buffer;
                        std::cout << task_message.c_str() << std::endl;
                        send(events[i].data.fd, task_message.c_str(), sizeof(task_message), 0);
                        user_datas[events[i].data.fd].buffer.erase(0, user_datas[events[i].data.fd].buffer.size());
                    }
                }

                if (handler_timer_task == true) // 这里采取定时器处理比io事件处理靠后，但是后面可以采取多线程
                {
                    std::cout << "handler_timer_task == true" << std::endl;
                    handler();
                    handler_timer_task = false;
                }
            }
        }
        close(pipefd[0]);
        close(pipefd[1]);
        close(pipefd[_listen_sockfd]);

        return;
    }

    void handler() // 定时模块处理函数
    {
        std::cout << "handler() 定时模块处理函数" << std::endl;
        timer_list.tick();
        alarm(TIME_SLOT); // 进行下一次定时
    }

    void addsig(int sig)
    {
        struct sigaction sa;
        memset(&sa, '\0', sizeof(sa));
        sa.sa_handler = sig_handler;
        sa.sa_flags |= SA_RESTART;
        sigemptyset(&sa.sa_mask);
        if (sigaction(sig, &sa, nullptr) == -1)
        {
            perror("sigaction");
            exit(EXIT_FAILURE);
        }
        std::cout << "addsig success" << std::endl;
    }

    static void sig_handler(int sig) // 信号处理函数
    {
        int save_errno = errno;
        int msg = sig;
        send(pipefd[1], (char *)&msg, 1, 0);
        errno = save_errno;
    }

    ~Server_Timer()
    {
    }

private:
    int _listen_sockfd;
    Epoll epoll;
    bool _isrunning = true;
    bool handler_timer_task;

    std::string ip;
    uint16_t port;

    // std::unique_ptr<User_Data[]> user_datas; // 用来保存客户信息，这个智能指针保存一个数组的首元素地址
    zj::client_data *user_datas;
};

// delete 清除资源，并且调用析构
// 智能指针

int main(int argc, char *argv[])
{

    std::string ip = argv[1];

    std::string port = argv[2];
    uint16_t port1 = std::stoi(port);
    alarm(TIME_SLOT * 3);
    std::unique_ptr<Server_Timer> ptr = std::make_unique<Server_Timer>(ip, port1);

    ptr->Server_start();

    return 0;
}